/*
 * Taobao.com Inc.
 * Copyright (c) 2000-2004 All Rights Reserved.
 */
package org.smartboot.maven.plugin.mydalgen.plugins.mybatis;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.smartboot.maven.plugin.mydalgen.PreferenceAware;
import org.smartboot.maven.plugin.mydalgen.plugins.mybatis.config.IWalletOperationConfig;
import org.smartboot.maven.plugin.mydalgen.plugins.mybatis.config.IWalletParamConfig;
import org.smartboot.maven.plugin.mydalgen.plugins.mybatis.util.DalUtil;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * @author Seer
 * @version IWalletOperation.java, v 0.1 2015年7月25日 上午10:23:28 Seer Exp.
 */
public abstract class IWalletOperation extends PreferenceAware implements Operation {
    public static final String PARAM_TYPE_OBJECT = "object";
    public static final String PARAM_TYPE_PRIMITIVE = "primitive";
    public static final String MULTIPLICITY_ONE = "one";
    public static final String MULTIPLICITY_MANY = "many";

    /**
     * an operation config instance holds operation configuration.
     */
    protected IWalletOperationConfig opConfig;
    /**
     * a list of all method parameters, each one is an instance of
     * IWalletParameter
     */
    protected List<Parameter> objectParams = new ArrayList<Parameter>();
    /**
     * a list of all method parameters, each one is an instance of
     * IWalletParameter
     */
    protected List<Parameter> primitiveParams = new ArrayList<Parameter>();
    /**
     * the type of how to pass parameters to dao
     */
    protected String paramType;
    /**
     * the multiplicity of results
     */
    protected String multiplicity;
    /**
     * the table instance
     */
    private IWalletTable table;

    /**
     * Constructor for IWalletOperation.
     */
    public IWalletOperation(IWalletOperationConfig conf) {
        super();
        opConfig = conf;
    }

    /**
     * @return
     * @see org.smartboot.maven.plugin.mydalgen.PreferenceAware#prefsPrefix()
     */
    @Override
    protected String prefsPrefix() {
        return "java-method";
    }

    /**
     * @return
     * @see org.smartboot.maven.plugin.mydalgen.plugins.mybatis.Operation#getName()
     */
    public String getName() {
        return opConfig.getName();
    }

    @Override
    public IWalletTable getTable() {
        return table;
    }

    /**
     * @param t
     */
    public void setTable(IWalletTable t) {
        table = t;

        setupParams();


        if (getParams().size() > 1) {
            // because we need a map to bundle all params.
            t.addIbatisImport("java.util.Map");
            t.addIbatisImport("java.util.HashMap");
        }

    }

    /**
     * @return
     */
    public List<Parameter> getParams() {
        if (PARAM_TYPE_OBJECT.equals(paramType)) {
            return objectParams;
        } else {
            // as default;
            return primitiveParams;
        }
    }

    /**
     * @return
     */
    public IWalletParameter getParam() {
        if (getParams().size() == 1) {
            return (IWalletParameter) getParams().get(0);
        } else {
            return null;
        }
    }

    public String getMappedStatementId() {
        return getName();
    }

    /**
     * @param origSql
     * @return
     */
    protected String getMappedStatementSql(String origSql) {
        if (StringUtils.isBlank(origSql)) {
            return origSql;
        }

        StringBuilder msSql = new StringBuilder();

        int startIndex = 0;
        int endIndex = origSql.indexOf("?");
        Iterator<Parameter> iParams = primitiveParams.iterator();

        while (endIndex >= 0 && iParams.hasNext()) {
            msSql.append(origSql, startIndex, endIndex);

            IWalletParameter param = (IWalletParameter) iParams.next();
            String paramName;

            if (PARAM_TYPE_PRIMITIVE.equals(paramType) && primitiveParams.size() == 1) {
                paramName = "value";
            } else {
                paramName = param.getName();
            }

            // 拼装sql语句
            msSql.append("#{").append(paramName).append("}");

            startIndex = endIndex + 1;
            endIndex = origSql.indexOf("?", startIndex);
        }

        msSql.append(origSql.substring(startIndex));
        return msSql.toString();
    }

    /**
     * Replace all parameter placeholders in parsedSql with their corresponding
     * names.
     *
     * @return
     */
    public String getMappedStatementSql() {
        String sql = null;
        if (opConfig.isHasSqlmap()) {
            // TODO: optimize the logic
            List<Parameter> params = getParams();
            List<String> paramNames = new ArrayList<String>();

            for (Parameter param : params) {
                paramNames.add(param.getName());
            }
            sql = opConfig.getSqlmap(paramNames);
        }
        return addSqlAnnotation(sql);
    }

    // added by yangyanzhao 2009-11-11
    public String addSqlAnnotation(String orgSql) {
        String idAnnotation = " ";
        String[] searchStrs = new String[]{"select", "SELECT", "insert", "INSERT", "delete", "DELETE", "update",
                "UPDATE"};
        int startOperation = StringUtils.indexOfAny(orgSql, searchStrs);
        if (-1 != startOperation) {
            String operation = StringUtils.substring(orgSql, 0, startOperation + 6);
            String afterOperation = StringUtils.substring(orgSql, startOperation + 7, orgSql.length());
            orgSql = operation + idAnnotation + afterOperation;
        }
        return orgSql;
    }

    /**
     * @return
     */
    public String getParamType() {
        return paramType;
    }

    /**
     * @return
     */
    public String getMultiplicity() {
        return multiplicity;
    }

    public String getParameterClass() {
        return opConfig.getParameterClass();
    }

    /**
     *
     */
    protected void setupParams() {
        IWalletTable iwTable = getTable();

        IWalletParameter param = new IWalletParameter(this, iwTable.getSingularisedVariableName());

        param.setPlugin(getPlugin());
        objectParams.add(param);

        if (PARAM_TYPE_OBJECT.equals(paramType)) {
            iwTable.addDaoImport(param.getQualifiedJavaType());
        }

        for (IWalletParamConfig paramConfig : opConfig.getExtraParams()) {
            param = new IWalletParameter(this, paramConfig.getName());
            param.setAnnotation(true);// operation/extraparams/param定义的参数适用Mybatis注解
            param.setJavaType(paramConfig.getJavaType());
            param.setGenericType(paramConfig.getGenericType());

            param.setPlugin(getPlugin());

            if (PARAM_TYPE_OBJECT.equals(paramType)) {
                objectParams.add(param);
            } else {
                primitiveParams.add(param);
            }
            iwTable.addDaoImport("org.apache.ibatis.annotations.Param");
            iwTable.addDaoImport(param.getQualifiedJavaType());
            iwTable.addIbatisImport(param.getQualifiedJavaType());
        }

        getReturnType();
    }

    /**
     * @return
     */
    public boolean isHasSqlmap() {
        return opConfig.isHasSqlmap();
    }

    public String getDescription() {
        return StringUtils.isNotBlank(opConfig.getDescription()) ? opConfig.getDescription() : "No descripions";
    }

//	public String getColumnType() {
//		SqlParser parser = opConfig.getSqlParser();
//
//		if (parser.isSelectItemSingle()) {
//			ZSelectItem item = parser.getSelectItem();
//
//			if (item.getAggregate() != null) {
//				// the select item is an aggregate
//				String aggregateFunc = item.getAggregate();
//
//				if (aggregateFunc.equalsIgnoreCase("COUNT")) {
//					return "long";
//				} else if (aggregateFunc.equalsIgnoreCase("SUM") || aggregateFunc.equalsIgnoreCase("AVG")
//					|| aggregateFunc.equalsIgnoreCase("MAX") || aggregateFunc.equalsIgnoreCase("MIN")) {
//					String columnName = item.getColumn();
//					int indexStart = columnName.indexOf("(");
//					int indexEnd = columnName.indexOf(")", indexStart);
//
//					columnName = columnName.substring(indexStart + 1, indexEnd);
//
//					return ((IWalletColumn) getTable().getColumn(columnName)).getJavaType();
//				} else {
//					// can not happen
//					return "void";
//				}
//			} else {
//				return ((IWalletColumn) getTable().getColumn(item.getColumn())).getJavaType();
//			}
//		} else {
//			return ((IWalletTable) getTable()).getQualifiedDOClassName();
//		}
//	}

}
